package com.braska.grave.netty.handler;

import com.alibaba.fastjson.JSON;
import com.braska.grave.netty.model.Request;
import com.braska.grave.netty.model.Response;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.commons.beanutils.MethodUtils;

import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * @author shenyuhang
 * @ChannelHandler.Sharable 标注一个handler可以被多个channel共享
 * @date 2020/3/30
 **/
@ChannelHandler.Sharable
public class NettyServerHandler extends ChannelInboundHandlerAdapter {
    private static final Logger logger = Logger.getLogger(NettyServerHandler.class.getName());
    private Map<String, Object> serviceMap;

    public NettyServerHandler(Map<String, Object> serviceMap) {
        this.serviceMap = serviceMap;
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        logger.info("客户端连接成功!" + ctx.channel().remoteAddress());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        logger.info(String.format("客户端断开连接! %s", ctx.channel().remoteAddress()));
        ctx.channel().close();
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        Request request = JSON.parseObject(msg.toString(), Request.class);
        if ("heartBeat".equals(request.getMethodName())) {
            logger.info("客户端心跳信息..."+ctx.channel().remoteAddress());
            return;
        }
        Response response = new Response();
        response.setRequestId(request.getId());
        try {
            Object res = this.handler(request);
            response.setData(res);
        } catch (Exception e) {
            response.setCode(-1);
            response.setError(e.getMessage());
            logger.log(Level.SEVERE, "请求调用失败", e);
        }
        ctx.writeAndFlush(response);
    }

    private Object handler(Request request) throws Exception {
        String className = request.getClassName();
        Object serviceBean = serviceMap.get(className);
        String methodName = request.getMethodName();
        Object[] parameters = request.getParameters();
        return MethodUtils.invokeMethod(serviceBean, methodName, parameters);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.log(Level.SEVERE, "网络异常.", cause);
        ctx.close();
    }
}
